package com.hwtx.form.persistence;

import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.Getter;

import java.io.IOException;
import java.util.Set;

@JsonSerialize(using = SQLType.CustomEnumSerializer.class)
@JsonDeserialize(using = SQLType.CustomEnumDeserializer.class)
public enum SQLType implements IEnum<Integer> {
    Tinyint(1, "Tinyint", "Tiny Integer", -1, null),
    Smallint(2, "Smallint", "Small Integer", -1, null),
    Mediumint(3, "Mediumint", "Medium Integer", null, null),
    Int(4, "Int", "Integer", -1, null),
    Bigint(5, "Bigint", "Big Integer", -1, null),
    Float(6, "Float", "Floating Point", -1, null),
    Double(7, "Double", "Double Precision", -1, null),
    Decimal(8, "Decimal", "Decimal Number", null, null),
    Date(9, "Date", "Date", -1, null),
    Time(10, "Time", "Time", -1, null),
    Datetime(11, "Datetime", "Date and Time", -1, null),
    Timestamp(12, "Timestamp", "Timestamp", -1, null),
    Year(13, "Year", "Year", -1, null),
    Char(14, "Char", "Character", null, null),
    Varchar(15, "Varchar", "Variable Character", null, null),
    Text(16, "Text", "Text", null, null),
    Mediumtext(17, "Mediumtext", "Medium Text", null, null),
    Longtext(18, "Longtext", "Long Text", null, null),
    Blob(19, "Blob", "Binary Large Object", null, null),
    Mediumblob(20, "Mediumblob", "Medium Binary Large Object", null, null),
    Longblob(21, "Longblob", "Long Binary Large Object", null, null),
    Json(22, "Json", "JSON", null, null),
    Tinyint_unsigned(23, "Tinyint unsigned", "Tiny unsigned Integer", -1, null),
    Smallint_unsigned(24, "Smallint unsigned", "Small unsigned Integer", -1, null),
    Mediumint_unsigned(25, "Mediumint unsigned", "Medium unsigned Integer", -1, null),
    Int_unsigned(26, "Int unsigned", "Int unsigned Integer", -1, null),
    Decimal_unsigned(27, "Decimal unsigned", "Decimal Unsigned Number", -1, null);

    private final int value;
    @Getter
    private final String desc;
    @Getter
    private final Integer precision;
    @Getter
    private final Integer scale;
    @Getter
    private final String name;

    SQLType(int value, String name, String desc, Integer precision, Integer scale) {
        this.value = value;
        this.name = name;
        this.desc = desc;
        this.precision = precision;
        this.scale = scale;
    }

    public static Set<SQLType> getNoCaseOfLengthAndPrecision() {
        return Set.of(Tinyint, Smallint, Mediumint, Int, Bigint, Float, Double, Decimal, Date, Time, Datetime, Timestamp, Year, Tinyint_unsigned, Smallint_unsigned, Mediumint_unsigned, Int_unsigned, Decimal_unsigned);
    }

    public static SQLType of(String type) {
        for (SQLType sqlType : SQLType.values()) {
            if (sqlType.name.equalsIgnoreCase(type)) {
                return sqlType;
            }
        }
        return null;
    }

    public static SQLType getType(String type) {
        return SQLType.of(type);
    }

    public static boolean isNumber(SQLType sqlType) {
        return sqlType == Tinyint || sqlType == Smallint || sqlType == Mediumint || sqlType == Int || sqlType == Bigint || sqlType == Float || sqlType == Double || sqlType == Decimal || sqlType == Tinyint_unsigned || sqlType == Smallint_unsigned || sqlType == Mediumint_unsigned || sqlType == Int_unsigned || sqlType == Decimal_unsigned;
    }

    public static boolean isDatetime(SQLType sqlType) {
        return sqlType == Datetime || sqlType == Timestamp;
    }

    public static boolean isDate(SQLType sqlType) {
        return sqlType == Date;
    }

    public static boolean isTime(SQLType sqlType) {
        return sqlType == Time;
    }

    public static boolean isString(SQLType sqlType) {
        return sqlType == Char || sqlType == Varchar || sqlType == Text || sqlType == Mediumtext || sqlType == Longtext || sqlType == Blob ||
                sqlType == Mediumblob || sqlType == Longblob || sqlType == Json;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }

    // 自定义序列化器
    static class CustomEnumSerializer extends StdSerializer<SQLType> {
        public CustomEnumSerializer() {
            super(SQLType.class);
        }

        @Override
        public void serialize(SQLType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(value.name);
        }
    }

    // 自定义反序列化器
    static class CustomEnumDeserializer extends StdDeserializer<SQLType> {
        public CustomEnumDeserializer() {
            super(SQLType.class);
        }

        @Override
        public SQLType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String enumString = p.getText();
            return SQLType.of(enumString);
        }
    }
}
